import spinal_loongarch_core132.{BoothEncode,WallaceTree}

import spinal.core._
import spinal.sim._
import spinal.core.sim._

import scala.util.Random

class MulForSim(val w:Int=8) extends Component{
    val io = new Bundle{
        val a    = in UInt(w bits)
        val b    = in UInt(w bits)
        val sign = in Bool()
        val p    = out UInt(2*w bits)
    }
    val x = ((io.sign && io.a.msb) ## io.a).asSInt
    val y = ((io.sign && io.b.msb) ## io.b).asSInt
    val bt = new BoothEncode(x,y)
    val wt = new WallaceTree(bt)
    io.p := wt.res.reduce(_+_)
}

//RegFile's testbench
object MulSim {
    val w:Int = 4
    val msk1:Long = (1L <<    w ) - 1L
    val msk2:Long = (1L << (2*w)) - 1L
    val sft:Long = (1L <<(w - 1))
    def getNext(s:Boolean) = (Random.nextLong()&msk1) - (if(s) sft else 0)
    def main(args: Array[String]) {
        SimConfig.withWave.doSim(new MulForSim(w)){dut =>
            def test(s:Boolean,a:Long,b:Long){
                val ia:Long = a & msk1
                val ib:Long = b & msk1
                dut.io.a #= ia
                dut.io.b #= ib
                dut.io.sign #= s
                sleep(1)
                val res:Long = dut.io.p.toLong & msk2
                val ans:Long = (a * b) & msk2
                if(res != ans){
                    printf(s"$ia * $ib should = ${ans} but got ${res}")
                }
                assert(res == ans)
                sleep(1)
            }
            for(idx <- 0 to 99){
                val s   = Random.nextBoolean()
                val a,b = getNext(s)
                test(s,a,b)
            }
        }
    }
}
